//========================================================================================
//  
//  $File: $
//  
//  Owner: Toan Nguyen
//  
//  $Author: $
//  
//  $DateTime: $
//  
//  $Revision: $
//  
//  $Change: $
//  
//  Copyright 1997-2008 Adobe Systems Incorporated. All rights reserved.
//  
//  NOTICE:  Adobe permits you to use, modify, and distribute this file in accordance 
//  with the terms of the Adobe license agreement accompanying it.  If you have received
//  this file from a source other than Adobe, then your use, modification, or 
//  distribution of it requires the prior written permission of Adobe.
//  
//========================================================================================
#include "VCPlugInHeaders.h"

// Interface includes

// Impl includes
#include <map>
#include "SDKFileHelper.h"
// Project includes
#include "AMPluginDataModel.h"
#include "IControlView.h"
#include "IPanelControlData.h"
#include "IPalettePanelUtils.h"
#include "AMPIssuesDataNode.h"


#include "JSONHelper.h"
#include "AMGlobal.h"


/**  Class representing a folder hierarchy. 
	@ingroup paneltreeview
*/
class AMPIssuesDataModel : CPMUnknown<AMPluginDataModel>
{
public:
	/** Default constructor */
	AMPIssuesDataModel(IPMUnknown* boss);

	/**	Destructor
	 */
	virtual ~AMPIssuesDataModel();

	/**		See AMPluginDataModel::GetRootPath 
	*/
	virtual PMString GetRootPath() const;

	/** 	See AMPluginDataModel::GetNode
	*/
	virtual AMPIssuesDataNode* GetNode(const PMString& path) const;


	/**		See AMPluginDataModel::GetParentPath
	 */
	virtual PMString GetParentPath(const PMString& path) const;

	/**		See AMPluginDataModel::GetChildCount
	 */
	virtual int32 GetChildCount(const PMString& path); 

	/**		See AMPluginDataModel::GetNthChildPath
	 */
	virtual PMString GetNthChildPath(const PMString& path, int32 nth); 

	/**		See AMPluginDataModel::GetChildIndexFor 
	 */
	virtual int32 GetChildIndexFor(const PMString& par, const PMString& kid); 


	/**	See AMPluginDataModel::Rebuild
	 */
	virtual void Rebuild(const PMString& rootPath);
	
	/** added by Vu Tiet to get display string
	 */
	virtual PMString GetRootName() const;
	
	virtual PMString GetParentName(const PMString& path) const;
	
	virtual PMString GetNthChildName(const PMString& path, int32 nth); 
	
	/** added by Vu Tiet to get image path
	 */
	virtual PMString GetRootImgPath() const;
	
	virtual PMString GetParentImgPath(const PMString& path) const;
	
	virtual PMString GetNthChildImgPath(const PMString& path, int32 nth); 
	
	
	// get node type
	virtual int GetRootType() const;
	
	virtual int GetParentType(const PMString& path) const;
	
	virtual int GetNthChildType(const PMString& path, int32 nth); 
	
	virtual int GetNthChildDataChecked(const PMString& path, int32 nth);
	
	virtual int GetRootIsCheck() const;
	
	virtual int GetParentIsCheck(const PMString& path) const;
	
	virtual void SetCurrentSelected(const PMString& path, const int typenode);
	
	virtual void GetParamNodeSelected(const PMString& parentPath, string *pageSelect, string *parentIssue);
	
	virtual int GetCurrentSelected(const PMString& path);
	
	virtual string GetIssueParentSelected(const PMString& path);
	
	virtual void RereshData(const PMString& parentPath);
	
	virtual void deleteData(const PMString& parentPath);
	
	virtual IControlView* GetWidgetOnPanel(const WidgetID& panelWidgetID, const WidgetID& widgetID);
	
	virtual int GetRootNumber() const;
	
	virtual int GetParentNumber(const PMString& path) const;
	
	virtual int GetNthChildNumber(const PMString& path, int32 nth); 
	
	virtual int GetNodeStatus(const PMString& parentPath);
	
	virtual int GetNodeIsEditing(const PMString& parentPath);
protected:

	/** Cache the kids of the given node in file system
	*/
	void cacheChildren(const PMString& path);
	
	/**	Determine if this is a path that we want to put in the data model
		@param p [IN] specifies path of interest
		@return bool16 if the path is a file system path of interest
	 */
	bool16 validPath(const PMString& p);

	/**	Destroy the tree represented in this 
	 */
	void deleteTree() ;
	
	bool16 isStory(const PMString& parentPath);
private:
	
	std::map<PMString, AMPIssuesDataNode* > fPathNodeMap;
	AMPIssuesDataNode* fRootNode;


};

/* CREATE_PMINTERFACE
 Binds the C++ implementation class onto its ImplementationID 
 making the C++ code callable by the application.
*/
CREATE_PMINTERFACE(AMPIssuesDataModel, kAMPIssuesDataModelImpl)


/* Constructor
*/
AMPIssuesDataModel::AMPIssuesDataModel(IPMUnknown* boss) : 
	CPMUnknown<AMPluginDataModel>(boss),
	fRootNode(nil)
{
}



	
/* Destructor
*/
AMPIssuesDataModel::~AMPIssuesDataModel()
{
	deleteTree();
}


/********************************************************************************************************************
 *****Function: deleteTree
 *****Creator:  Toan Nguyen
 *****IN: 
 *****out: 
 *****Objective: 
 ********************************************************************************************************************/
void AMPIssuesDataModel::deleteTree() 
{
	// We've flattened the tree in our hashtable anyway so 
	// use this to delete the nodes.
	std::map<PMString, AMPIssuesDataNode* >::iterator iter;
	for(iter = fPathNodeMap.begin(); iter != fPathNodeMap.end(); iter++)
	{
		AMPIssuesDataNode* node = iter->second;
		ASSERT(node);
		delete node;
		//cout << "deleteTree delete node" << endl;
	
	}
	fPathNodeMap.clear();
	fRootNode = nil;
	//cout << "deleteTree set fRootNode=nil" << endl;
}


/********************************************************************************************************************
 *****Function: Rebuild
 *****Creator:  Toan Nguyen
 *****IN: 
 *****out: 
 *****Objective: 
 ********************************************************************************************************************/
void AMPIssuesDataModel::Rebuild(const PMString& path)
{
	if(fRootNode != nil) {
		deleteTree();
	}
	if(path.empty() == kFalse) {
		fRootNode =  new AMPIssuesDataNode();
		//cout << "fRootNode path " << path.GrabCString() << endl;
		fRootNode->SetData(path);
		fRootNode->SetNodeName(path);
		fRootNode->setType(ROOT_NODE);
		fRootNode->setNodeSelect(NODE_UNSELECTED);
		fPathNodeMap.insert( std::pair<PMString, AMPIssuesDataNode* >(path, fRootNode));
		this->cacheChildren(path);
	}

}


/********************************************************************************************************************
 *****Function: GetParentPath
 *****Creator:  Toan Nguyen
 *****IN: 
 *****out: 
 *****Objective: 
 ********************************************************************************************************************/
PMString  AMPIssuesDataModel::GetParentPath(const PMString& path) const
{
	// We assume that the parent is cached, because we
	// found its kids
	std::map<PMString, AMPIssuesDataNode* >::const_iterator result = fPathNodeMap.find(path);
	if(result != fPathNodeMap.end())
	{
		AMPIssuesDataNode* node = result->second;
		ASSERT(node);
		ASSERT(fRootNode);
		// Use the comparison we've defined on the node class
		if((*node) == (*fRootNode))
		{
			return PMString();
		}
		return node->GetParent()->GetData();
	}
	return PMString();
}


/********************************************************************************************************************
 *****Function: GetChildCount
 *****Creator:  Toan Nguyen
 *****IN: 
 *****out: 
 *****Objective: 
 ********************************************************************************************************************/
int32 AMPIssuesDataModel::GetChildCount(const PMString& path) // not const any more
{
	std::map<PMString, AMPIssuesDataNode* >::const_iterator result = fPathNodeMap.find(path);
	if(result != fPathNodeMap.end()) {
		int32 possChildCount = result->second->ChildCount();
		if(possChildCount > 0) {
			// Don't trust a zero value, it may just be we didn't yet cache the kids
			return possChildCount;
		}
	}
	// So, we may not have cached the kids.
	this->cacheChildren(path);
	// Don't recurse, as we may have no kids and we only want one try
	std::map<PMString, AMPIssuesDataNode* >::const_iterator postCacheResult = fPathNodeMap.find(path);
	if(postCacheResult != fPathNodeMap.end()) {
		return postCacheResult->second->ChildCount();
	}
	return 0;
}

/********************************************************************************************************************
 *****Function: GetNthChildPath
 *****Creator:  Toan Nguyen
 *****IN: 
 *****out: 
 *****Objective: 
 ********************************************************************************************************************/
PMString AMPIssuesDataModel::GetNthChildPath(
	const PMString& path, int32 nth) // not const any more
{
	std::map<PMString, AMPIssuesDataNode* >::const_iterator result = fPathNodeMap.find(path);
	if(result != fPathNodeMap.end()) {
		int32 possChildCount = result->second->ChildCount();
		if(possChildCount > 0) {
			// Again, distrust a node with zero child count, may be kids not yet cached 
			return result->second->GetNthChild(nth).GetData();
		}
	}
	// Again, we may not have cached the kids.
	this->cacheChildren(path);
	// Don't recurse, as we may have no kids and we only want one try
	std::map<PMString, AMPIssuesDataNode* >::const_iterator postCacheResult = fPathNodeMap.find(path);
	if(postCacheResult != fPathNodeMap.end()) {
		return postCacheResult->second->GetNthChild(nth).GetData();
	}

	return PMString();
}

/********************************************************************************************************************
 *****Function: GetChildIndexFor
 *****Creator:  Toan Nguyen
 *****IN: 
 *****out: 
 *****Objective: 
 ********************************************************************************************************************/
int32  AMPIssuesDataModel::GetChildIndexFor(
	const PMString& par, const PMString& kid) //const
{
	// Can we be called here without the kids being already cached?
	int32 retval=(-1);
	std::map<PMString, AMPIssuesDataNode* >::const_iterator result = fPathNodeMap.find(par);
	if(result != fPathNodeMap.end()) {
		AMPIssuesDataNode* node = result->second;
		if(node->ChildCount() == 0) {
			// Try to cache the kids, we may not have done so
			this->cacheChildren(par);
		}
		for(int32 i=0; i < node->ChildCount(); i++){
			PMString kidPath = node->GetNthChild(i).GetData();
			if(kid == kidPath) {
				retval=i;
				break;
			}
		}
	}
	
	return retval;
}


/********************************************************************************************************************
 *****Function: GetRootPath
 *****Creator:  Toan Nguyen
 *****IN: 
 *****out: 
 *****Objective: 
 ********************************************************************************************************************/
PMString AMPIssuesDataModel::GetRootPath() const
{
	if(fRootNode != nil)
	{
		return fRootNode->GetData();
	}
	return PMString();
}

/********************************************************************************************************************
 *****Function: GetNode
 *****Creator:  Toan Nguyen
 *****IN: 
 *****out: 
 *****Objective: 
 ********************************************************************************************************************/
AMPIssuesDataNode* AMPIssuesDataModel::GetNode(const PMString& path) const
{
	AMPIssuesDataNode* retval = nil;

	std::map<PMString, AMPIssuesDataNode* >::const_iterator result = fPathNodeMap.find(path);
	if(result != fPathNodeMap.end()) {
		retval = result->second;
	}
	return retval;
}

/********************************************************************************************************************
 *****Function: validPath
 *****Creator:  Toan Nguyen
 *****IN: 
 *****out: 
 *****Objective: 
 ********************************************************************************************************************/
bool16 AMPIssuesDataModel::validPath(const PMString& p)
{
	const PMString thisDir(".");
	const PMString parentDir("..");
	return p != thisDir && p != parentDir;
}


/*

void AMPIssuesDataModel::cacheChildren(const PMString& parentPath)
{
#if 1
	int16 i;
	char * pDatabase[8] = {"April 2011", "May 2011", "April 2012", "June 2012","July 2012", "August 2012", "October 2012", "chi"};
	int issueSize = g_Magazines[0]._issueSize;
	cout << "issueSize " << issueSize << endl;
	//char *pDatabase[issueSize];
	
	AMPIssuesDataNode* parentNode = nil;
	std::map<PMString, AMPIssuesDataNode* >::const_iterator iterForParent = fPathNodeMap.find(parentPath);
	if(iterForParent == fPathNodeMap.end()) {
		return;
	}
	parentNode = iterForParent->second;
	ASSERT(parentNode);

	for (i =0; i< issueSize; i++)
	{
		//PMString newParent(pDatabase[i]);
		
		//std::string s;
		//std::stringstream out;
		//out << i;
		//s = out.str();
		//string iStr = g_Magazines[0]._issues[i]._name + s;
		//PMString newParent(iStr.c_str());
		
		PMString newParent(g_Magazines[0]._issues[i]._name.c_str());
		AMPIssuesDataNode* newNode = new AMPIssuesDataNode();
		newNode->SetData(newParent);
		newNode->SetParent(parentNode);
		parentNode->AddChild(static_cast<const AMPIssuesDataNode& >(*newNode));

		fPathNodeMap.insert( std::pair<PMString, AMPIssuesDataNode* >(newParent, newNode));
		addNtChildren(newParent, i);
	}
#else
	do
	{
		char * pDatabase[4] = {"nguyen", "minh", "toan", "abcde"};
		AMPIssuesDataNode* parentNode = nil;
		std::map<PMString, AMPIssuesDataNode* >::const_iterator iterForParent = fPathNodeMap.find(parentPath);
		if(iterForParent == fPathNodeMap.end()) {
			break;
		}
		parentNode = iterForParent->second;
		ASSERT(parentNode);

		SDKFileHelper parentFileHelper(parentPath);
		IDFile parIDFile = parentFileHelper.GetIDFile();
		PlatformFileSystemIterator iter;
		if(!iter.IsDirectory(parIDFile)){
			break;
		}
		iter.SetStartingPath(parIDFile);

		IDFile idFile;
		PMString filter("\\*.*");
		bool16 hasNext= iter.FindFirstFile(idFile, filter);

		while(hasNext) {
			SDKFileHelper fileHelper(idFile);
			// Insert will fail if the item is there already... 
			// so look to see if we have a node already and erase if we have
			std::map<PMString, AMPIssuesDataNode* >::iterator existingIter 
				= fPathNodeMap.find(fileHelper.GetPath());
			if(existingIter != fPathNodeMap.end()) {
				// See Docs on UniqueAssociativeContainer and look at insert semantics
				// http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
				AMPIssuesDataNode* existingNodeBeingReplaced = existingIter->second;
				delete existingNodeBeingReplaced;
				fPathNodeMap.erase(existingIter);
			}

			PMString truncP = idFile.GetFileName();
			if(validPath(truncP))
			{
				AMPIssuesDataNode* newNode = new AMPIssuesDataNode();
				newNode->SetData(fileHelper.GetPath());
				newNode->SetParent(parentNode);
				parentNode->AddChild(static_cast<const AMPIssuesDataNode& >(*newNode));

				fPathNodeMap.insert( std::pair<PMString, AMPIssuesDataNode* >(fileHelper.GetPath(), newNode));
			}
			hasNext= iter.FindNextFile(idFile);
		}
	} while(kFalse);
#endif
}
 */

/********************************************************************************************************************
 *****Function: cacheChildren
 *****Creator:  Toan Nguyen
 *****IN: const PMString& parentPath
 *****out: 
 *****Objective: 
 ********************************************************************************************************************/
void AMPIssuesDataModel::cacheChildren(const PMString& parentPath)
{
	do
	{
		//cout << "cacheChildren parentPath:" << parentPath.GrabCString() << endl;
		AMPIssuesDataNode* parentNode = nil;
		std::map<PMString, AMPIssuesDataNode* >::const_iterator iterForParent = fPathNodeMap.find(parentPath);
		if(iterForParent == fPathNodeMap.end()) {
			break;
		}
		parentNode = iterForParent->second;
		ASSERT(parentNode);
		
		int curType = parentNode->getType();
		string curPath = parentNode->GetData().GrabCString();
		//cout << "currentNode: " << curPath << " --- type: " << curType << endl;
		if (parentNode->getType() == STORY_NODE) {
			break;
		}
		
		/////////////////////////////////////
		// ROOT_NODE
		/////////////////////////////////////
		if (parentNode->getType() == ROOT_NODE) {
			// add magazines
			for (int i = 0; i < g_Magazine_Count; i++) {
				// Insert will fail if the item is there already... 
				// so look to see if we have a node already and erase if we have
				std::map<PMString, AMPIssuesDataNode* >::iterator existingIter 
				= fPathNodeMap.find(g_Magazines[i]._id.c_str());
				if(existingIter != fPathNodeMap.end()) {
					// See Docs on UniqueAssociativeContainer and look at insert semantics
					// http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
					AMPIssuesDataNode* existingNodeBeingReplaced = existingIter->second;
					delete existingNodeBeingReplaced;
					fPathNodeMap.erase(existingIter);
				}
				
				AMPIssuesDataNode* newNode = new AMPIssuesDataNode();
				newNode->SetData(g_Magazines[i]._id.c_str());
				newNode->setType(MAG_NODE);
				newNode->setNodeSelect(NODE_UNSELECTED);
				newNode->SetNodeName(g_Magazines[i]._name.c_str());
				newNode->setNodeID(g_Magazines[i]._id.c_str());
				newNode->setNodeImgPath(g_SDK_WorkspaceDir.c_str());
				newNode->SetNodeNumber(-1);
				newNode->SetParent(parentNode);
				parentNode->AddChild(static_cast<const AMPIssuesDataNode& >(*newNode));					
				fPathNodeMap.insert( std::pair<PMString, AMPIssuesDataNode* >(g_Magazines[i]._id.c_str(), newNode));				
			}
		} 
		
		/////////////////////////////////////
		// MAG_NODE
		/////////////////////////////////////		
		if (parentNode->getType() == MAG_NODE) {
			// get the right magazine
			int magazineIndex;
			for (int ii = 0; ii < g_Magazine_Count; ii++) {
				string curIssuePath = g_Magazines[ii]._id;
				PMString magID(curIssuePath.c_str());
				if (parentPath.Compare(true, magID) == 0) {
					magazineIndex = ii;
					break;
				}
				
			}
			
			// add issues
			for (int i = 0; i < g_Magazines[magazineIndex]._issueSize; i++) {
				
				// create issue path
				string issuePath = g_Magazines[magazineIndex]._id + "/" + g_Magazines[magazineIndex]._issues[i]._id;
				//cout << "issuePath " << issuePath << endl;
				
				// Insert will fail if the item is there already... 
				// so look to see if we have a node already and erase if we have
				//std::map<PMString, AMPIssuesDataNode* >::iterator existingIter 
				//= fPathNodeMap.find(g_Magazines[0]._issues[i]._id.c_str());
				std::map<PMString, AMPIssuesDataNode* >::iterator existingIter 
				= fPathNodeMap.find(issuePath.c_str());
				if(existingIter != fPathNodeMap.end()) {
					// See Docs on UniqueAssociativeContainer and look at insert semantics
					// http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
					AMPIssuesDataNode* existingNodeBeingReplaced = existingIter->second;
					delete existingNodeBeingReplaced;
					fPathNodeMap.erase(existingIter);
				}
				
				AMPIssuesDataNode* newNode = new AMPIssuesDataNode();
				//newNode->SetData(g_Magazines[0]._issues[i]._id.c_str());
				newNode->SetData(issuePath.c_str());
				newNode->setType(ISSUE_NODE);
				newNode->setNodeSelect(NODE_UNSELECTED);
				newNode->SetNodeName(g_Magazines[magazineIndex]._issues[i]._name.c_str());
				newNode->setNodeID(g_Magazines[magazineIndex]._issues[i]._id.c_str());
				newNode->setNodeImgPath(g_SDK_WorkspaceDir.c_str());
				newNode->SetNodeNumber(-1);
				newNode->SetParent(parentNode);
				parentNode->AddChild(static_cast<const AMPIssuesDataNode& >(*newNode));					
				//fPathNodeMap.insert( std::pair<PMString, AMPIssuesDataNode* >(g_Magazines[0]._issues[i]._id.c_str(), newNode));
				fPathNodeMap.insert( std::pair<PMString, AMPIssuesDataNode* >(issuePath.c_str(), newNode));
			}
			
		}
		
		/////////////////////////////////////
		// ISSUE_NODE
		/////////////////////////////////////		
		if (parentNode->getType() == ISSUE_NODE) {
			// get the right issue
			int magazineIndex;
			int issueIndex;
			for (int h = 0; h < g_Magazine_Count; h++) {
				for (int i = 0; i < g_Magazines[h]._issueSize; i++) {
					string curIssuePath = g_Magazines[h]._id + "/" + g_Magazines[h]._issues[i]._id;
					//PMString issueID(g_Magazines[0]._issues[i]._id.c_str());
					PMString issueID(curIssuePath.c_str());
					if (parentPath.Compare(true, issueID) == 0) {
						magazineIndex = h;
						issueIndex = i;
						break;
					}
				}
			}
			
			// add pages
			for (int j = 0; j < g_Magazines[magazineIndex]._issues[issueIndex]._pageSize; j++) {
				
				// create page path
				string pagePath = g_Magazines[magazineIndex]._id + "/" + g_Magazines[magazineIndex]._issues[issueIndex]._id + "/" + g_Magazines[magazineIndex]._issues[issueIndex]._pages[j]._id;
				//cout << "pagePath " << pagePath << endl;

				
				// Insert will fail if the item is there already... 
				// so look to see if we have a node already and erase if we have
				//std::map<PMString, AMPIssuesDataNode* >::iterator existingIter 
				//= fPathNodeMap.find(g_Magazines[0]._issues[issueIndex]._pages[j]._id.c_str());
				std::map<PMString, AMPIssuesDataNode* >::iterator existingIter 
				= fPathNodeMap.find(pagePath.c_str());
				if(existingIter != fPathNodeMap.end()) {
					// See Docs on UniqueAssociativeContainer and look at insert semantics
					// http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
					AMPIssuesDataNode* existingNodeBeingReplaced = existingIter->second;
					delete existingNodeBeingReplaced;
					fPathNodeMap.erase(existingIter);
				}
				
				AMPIssuesDataNode* newNode = new AMPIssuesDataNode();
				//newNode->SetData(g_Magazines[0]._issues[issueIndex]._pages[j]._id.c_str());
				newNode->SetData(pagePath.c_str());
				newNode->setType(PAGE_NODE);
				//cout << "newNode->setNodeSelect(NODE_UNSELECTED);" << endl;
				newNode->setNodeSelect(NODE_UNSELECTED);
				newNode->setNodeEditing(NODE_NOTEDITING);
				if( (g_Issueid != "") && (g_pageNumberCheckOut != "") && 
				   (g_Magazines[magazineIndex]._issues[issueIndex]._id == g_Issueid))
				{
					int pageNum = g_Magazines[magazineIndex]._issues[issueIndex]._pages[j]._number;
					stringstream ss;
					ss << pageNum;
					string PageChecktmp = " " + ss.str() + ",";
					if(g_pageNumberCheckOut.find(PageChecktmp) != string::npos)
					{
						newNode->setNodeSelect(NODE_SELECTED);
					}
				}
				if( (g_issueEditing != "") && (g_pageEditing != "") && 
				   (g_Magazines[magazineIndex]._issues[issueIndex]._id == g_issueEditing))
				{
					int pageNum = g_Magazines[magazineIndex]._issues[issueIndex]._pages[j]._number;
					stringstream ss;
					ss << pageNum;
					string PageChecktmp = " " + ss.str() + ",";
					if(g_pageEditing.find(PageChecktmp) != string::npos)
					{
						newNode->setNodeEditing(NODE_EDITING);
					}
				}
				newNode->SetNodeName(g_Magazines[magazineIndex]._issues[issueIndex]._pages[j]._name.c_str());
				newNode->setNodeID(g_Magazines[magazineIndex]._issues[issueIndex]._pages[j]._id.c_str());
				newNode->setNodeImgPath(g_Magazines[magazineIndex]._issues[issueIndex]._pages[j]._localImagePath.c_str());
				//cout << "newNode->setNodeImgPath: " << newNode->GetNodeName().GrabCString() << " - " << g_Magazines[magazineIndex]._issues[issueIndex]._pages[j]._localImagePath.c_str() << endl;
				newNode->SetNodeNumber(g_Magazines[magazineIndex]._issues[issueIndex]._pages[j]._number);
				newNode->setNodeStatus(g_Magazines[magazineIndex]._issues[issueIndex]._pages[j]._status);	//added status
				newNode->SetParent(parentNode);
				parentNode->AddChild(static_cast<const AMPIssuesDataNode& >(*newNode));					
				//fPathNodeMap.insert( std::pair<PMString, AMPIssuesDataNode* >(g_Magazines[0]._issues[issueIndex]._pages[j]._id.c_str(), newNode));
				fPathNodeMap.insert( std::pair<PMString, AMPIssuesDataNode* >(pagePath.c_str(), newNode));
				//cout << "inserted pagePath " << pagePath << endl;
			}
		}
		
		/////////////////////////////////////
		// PAGE_NODE
		/////////////////////////////////////		
		if (parentNode->getType() == PAGE_NODE) {
			
			// get the right page
			int magazineIndex;
			int issueIndex;
			int pageIndex;
			for (int h = 0; h < g_Magazine_Count; h++) {
				for (int i = 0; i < g_Magazines[h]._issueSize; i++) {
					for (int j = 0; j < g_Magazines[h]._issues[i]._pageSize; j++) {
						string curPagePath = g_Magazines[h]._id + "/" + g_Magazines[h]._issues[i]._id + "/" + g_Magazines[h]._issues[i]._pages[j]._id;
						//PMString pageID(g_Magazines[0]._issues[i]._pages[j]._id.c_str());
						PMString pagePath(curPagePath.c_str());
						if (parentPath.Compare(true, pagePath) == 0) {
							magazineIndex = h;
							issueIndex = i;
							pageIndex = j;
							break;
						}
					}
				}
			}
			
			// add stories
			for (int k = 0; k < g_Magazines[magazineIndex]._issues[issueIndex]._pages[pageIndex]._storySize; k++) {
				// create story path
				string storyPath = g_Magazines[magazineIndex]._id + "/" + g_Magazines[magazineIndex]._issues[issueIndex]._id + "/" + g_Magazines[magazineIndex]._issues[issueIndex]._pages[pageIndex]._id + "/" + g_Magazines[magazineIndex]._issues[issueIndex]._pages[pageIndex]._stories[k]._id;
				//cout << "storyPath " << storyPath << endl;
				
				// Insert will fail if the item is there already... 
				// so look to see if we have a node already and erase if we have
				//std::map<PMString, AMPIssuesDataNode* >::iterator existingIter 
				//= fPathNodeMap.find(g_Magazines[0]._issues[issueIndex]._pages[pageIndex]._stories[k]._id.c_str());
				std::map<PMString, AMPIssuesDataNode* >::iterator existingIter 
				= fPathNodeMap.find(storyPath.c_str());
				if(existingIter != fPathNodeMap.end()) {
					// See Docs on UniqueAssociativeContainer and look at insert semantics
					// http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
					AMPIssuesDataNode* existingNodeBeingReplaced = existingIter->second;
					delete existingNodeBeingReplaced;
					fPathNodeMap.erase(existingIter);
				}
				
				AMPIssuesDataNode* newNode = new AMPIssuesDataNode();
				//newNode->SetData(g_Magazines[0]._issues[issueIndex]._pages[pageIndex]._stories[k]._id.c_str());
				newNode->SetData(storyPath.c_str());
				newNode->SetNodeName(g_Magazines[magazineIndex]._issues[issueIndex]._pages[pageIndex]._stories[k]._name.c_str());
				//cout << "setNodeName: " << g_Magazines[magazineIndex]._issues[issueIndex]._pages[pageIndex]._stories[k]._name.c_str() << endl;
				newNode->setNodeID(g_Magazines[magazineIndex]._issues[issueIndex]._pages[pageIndex]._stories[k]._id.c_str());
				newNode->setType(STORY_NODE);
				newNode->setNodeSelect(NODE_UNSELECTED);
				newNode->setNodeImgPath(g_SDK_WorkspaceDir.c_str());
				newNode->SetNodeNumber(-1);
				newNode->setNodeStatus(g_Magazines[magazineIndex]._issues[issueIndex]._pages[pageIndex]._stories[k]._status);
				newNode->SetParent(parentNode);
				parentNode->AddChild(static_cast<const AMPIssuesDataNode& >(*newNode));					
				//fPathNodeMap.insert( std::pair<PMString, AMPIssuesDataNode* >(g_Magazines[0]._issues[issueIndex]._pages[pageIndex]._stories[k]._id.c_str(), newNode));
				fPathNodeMap.insert( std::pair<PMString, AMPIssuesDataNode* >(storyPath.c_str(), newNode));

				

				//cout << "node name: " << newNode->GetNodeName().GrabCString() << endl;

			}
		}
		
	} while(kFalse);
	//cout << "end cacheChildren" << endl;

}

/********************************************************************************************************************
 *****Function: isStory
 *****Creator:  Toan Nguyen
 *****IN: const PMString& parentPath
 *****out: 
 *****Objective: 
 ********************************************************************************************************************/
bool16 isStory(const PMString& parentPath) {
	
	for (int i = 0; i < g_Magazines[0]._issueSize; i++) 
		for (int j = 0; j < g_Magazines[0]._issues[i]._pageSize; j++) 
			for (int k = 0; k < g_Magazines[0]._issues[i]._pages[j]._storySize; k++) {
				PMString storyID(g_Magazines[0]._issues[i]._pages[j]._stories[k]._id.c_str());
				if (parentPath.Compare(true, storyID) == 0)
					return true;
			}
	return false;
}

/********************************************************************************************************************
 *****Function: GetRootName
 *****Creator:  Toan Nguyen
 *****IN: 
 *****out: 
 *****Objective: 
 ********************************************************************************************************************/
PMString AMPIssuesDataModel::GetRootName() const {
	if(fRootNode != nil)
	{
		return fRootNode->GetNodeName();
	}
	return PMString();
}

/********************************************************************************************************************
 *****Function: GetParentName
 *****Creator:  Toan Nguyen
 *****IN: 
 *****out: 
 *****Objective: 
 ********************************************************************************************************************/
PMString AMPIssuesDataModel::GetParentName(const PMString& path) const {
	// We assume that the parent is cached, because we
	// found its kids
	std::map<PMString, AMPIssuesDataNode* >::const_iterator result = fPathNodeMap.find(path);
	if(result != fPathNodeMap.end())
	{
		AMPIssuesDataNode* node = result->second;
		ASSERT(node);
		ASSERT(fRootNode);
		// Use the comparison we've defined on the node class
		if((*node) == (*fRootNode))
		{
			return PMString();
		}
		return node->GetParent()->GetNodeName();
	}
	return PMString();
}

/********************************************************************************************************************
 *****Function: GetNthChildName
 *****Creator:  Toan Nguyen
 *****IN: 
 *****out: 
 *****Objective: 
 ********************************************************************************************************************/
PMString AMPIssuesDataModel::GetNthChildName(const PMString& path, int32 nth) {
	std::map<PMString, AMPIssuesDataNode* >::const_iterator result = fPathNodeMap.find(path);
	if(result != fPathNodeMap.end()) {
		int32 possChildCount = result->second->ChildCount();
		if(possChildCount > 0) {
			// Again, distrust a node with zero child count, may be kids not yet cached 
			//cout << "++++++ GetNthChildName: " << result->second->GetNthChild(nth).GetNodeName().GrabCString() << endl;
			return result->second->GetNthChild(nth).GetNodeName();
		}
	}
	// Again, we may not have cached the kids.
	this->cacheChildren(path);
	// Don't recurse, as we may have no kids and we only want one try
	std::map<PMString, AMPIssuesDataNode* >::const_iterator postCacheResult = fPathNodeMap.find(path);
	if(postCacheResult != fPathNodeMap.end()) {
		//cout << "======= GetNthChildName: " << postCacheResult->second->GetNthChild(nth).GetNodeName().GrabCString() << endl;
		return postCacheResult->second->GetNthChild(nth).GetNodeName();
	}
	
	return PMString();
} 

/********************************************************************************************************************
 *****Function: GetRootImgPath
 *****Creator:  Toan Nguyen
 *****IN: 
 *****out: 
 *****Objective: 
 ********************************************************************************************************************/
PMString AMPIssuesDataModel::GetRootImgPath() const {
	if(fRootNode != nil)
	{
		return fRootNode->GetNodeImgPath();
	}
	return PMString();
}

/********************************************************************************************************************
 *****Function: GetParentImgPath
 *****Creator:  Toan Nguyen
 *****IN: 
 *****out: 
 *****Objective: 
 ********************************************************************************************************************/
PMString AMPIssuesDataModel::GetParentImgPath(const PMString& path) const {
	// We assume that the parent is cached, because we
	// found its kids
	//cout << "GetParentImgPath Path= " << path.GrabCString() << endl;
	std::map<PMString, AMPIssuesDataNode* >::const_iterator result = fPathNodeMap.find(path);
	if(result != fPathNodeMap.end())
	{
		AMPIssuesDataNode* node = result->second;
		ASSERT(node);
		ASSERT(fRootNode);
		// Use the comparison we've defined on the node class
		if((*node) == (*fRootNode))
		{
			return PMString();
		}
		return node->GetParent()->GetNodeImgPath();
	}
	return PMString();
	
}

/********************************************************************************************************************
 *****Function: GetNthChildImgPath
 *****Creator:  Toan Nguyen
 *****IN: 
 *****out: 
 *****Objective: 
 ********************************************************************************************************************/
PMString AMPIssuesDataModel::GetNthChildImgPath(const PMString& path, int32 nth) {
	std::map<PMString, AMPIssuesDataNode* >::const_iterator result = fPathNodeMap.find(path);
	if(result != fPathNodeMap.end()) {
		int32 possChildCount = result->second->ChildCount();
		if(possChildCount > 0) {
			// Again, distrust a node with zero child count, may be kids not yet cached 
			return result->second->GetNthChild(nth).GetNodeImgPath();
		}
	}
	// Again, we may not have cached the kids.
	this->cacheChildren(path);
	// Don't recurse, as we may have no kids and we only want one try
	std::map<PMString, AMPIssuesDataNode* >::const_iterator postCacheResult = fPathNodeMap.find(path);
	if(postCacheResult != fPathNodeMap.end()) {
		return postCacheResult->second->GetNthChild(nth).GetNodeImgPath();
	}
	
	return PMString();

}

/********************************************************************************************************************
 *****Function: GetRootType
 *****Creator:  Toan Nguyen
 *****IN: 
 *****out: 
 *****Objective: 
 ********************************************************************************************************************/
int AMPIssuesDataModel::GetRootType() const {
	if(fRootNode != nil)
	{
		return fRootNode->getType();
	}
	return -1;
}

/********************************************************************************************************************
 *****Function: GetRootIsCheck
 *****Creator:  Toan Nguyen
 *****IN: 
 *****out: 
 *****Objective: 
 ********************************************************************************************************************/
int AMPIssuesDataModel::GetRootIsCheck() const {
	if(fRootNode != nil)
	{
		return fRootNode->getNodeSelect();
	}
	return -1;
}

/********************************************************************************************************************
 *****Function: GetParentType
 *****Creator:  Toan Nguyen
 *****IN: const PMString& path
 *****out: 
 *****Objective: 
 ********************************************************************************************************************/
int AMPIssuesDataModel::GetParentType(const PMString& path) const {
	// We assume that the parent is cached, because we
	// found its kids
	
	//cout << "GetParentType Path= " << path.GrabCString() << endl;
	std::map<PMString, AMPIssuesDataNode* >::const_iterator result = fPathNodeMap.find(path);
	if(result != fPathNodeMap.end())
	{
		AMPIssuesDataNode* node = result->second;
		ASSERT(node);
		ASSERT(fRootNode);
		// Use the comparison we've defined on the node class
		if((*node) == (*fRootNode))
		{
			return -1;
		}
		//cout << "fPathData:" << node->GetParent()->GetData().GrabCString() << endl;
		//cout << "fNodeImgPath:" << node->GetParent()->GetNodeImgPath().GrabCString() << endl;
		//cout << "nodeType:" << node->GetParent()->getType() << endl;
		return node->GetParent()->getType();
	}
	
		
	return -1;
	
}

/********************************************************************************************************************
 *****Function: GetParentIsCheck
 *****Creator:  Toan Nguyen
 *****IN: const PMString& path
 *****out: 
 *****Objective: 
 ********************************************************************************************************************/
int AMPIssuesDataModel::GetParentIsCheck(const PMString& path) const {
	// We assume that the parent is cached, because we
	// found its kids
	//cout << "GetParentIsCheck Path= " << path.GrabCString() << endl;
	std::map<PMString, AMPIssuesDataNode* >::const_iterator result = fPathNodeMap.find(path);
	if(result != fPathNodeMap.end())
	{
		AMPIssuesDataNode* node = result->second;
		ASSERT(node);
		ASSERT(fRootNode);
		// Use the comparison we've defined on the node class
		if((*node) == (*fRootNode))
		{
			return -1;
		}
		//cout << "node->GetParentIsCheck: " << path.GrabCString() << endl;
		return node->GetParent()->getNodeSelect();
	}
	return -1;
	
}

/********************************************************************************************************************
 *****Function: SetCurrentSelected
 *****Creator:  Toan Nguyen
 *****IN: const PMString& parentPath, const int typenode
 *****out: 
 *****Objective: 
 ********************************************************************************************************************/
void AMPIssuesDataModel::SetCurrentSelected(const PMString& parentPath, const int typenode)  {
	// We assume that the parent is cached, because we
	// found its kidS
	do
	{
		AMPIssuesDataNode* parentNode = nil;
		std::map<PMString, AMPIssuesDataNode* >::const_iterator iterForParent = fPathNodeMap.find(parentPath);
		//std::map<PMString, AMPIssuesDataNode* >::iterator iterForParent = fPathNodeMap.find(tmpPath);
		if(iterForParent == fPathNodeMap.end()) {
			break;
		}
		parentNode = iterForParent->second;
		ASSERT(parentNode);
		
		int curType = parentNode->getType();
		string curPath = parentNode->GetData().GrabCString();
		parentNode->setNodeSelect(typenode);
		//cout << "++++++++++++++++++++++++++++++++++++" << endl;
		//cout << "parentPath3: " << parentNode->GetData().GrabCString() << endl;
		//cout << "parentName3: " << parentNode->GetNodeName().GrabCString() << endl;
		//cout << "parentImgPath3: " << parentNode->GetNodeID().GrabCString() << endl;
		//cout << "GetNodeImgPath3: " << parentNode->GetNodeImgPath().GrabCString() << endl;
		//cout << "parentDataType3: " << parentNode->getNodeSelect() << endl;
		//cout << "parentDataCheck3: " << parentNode->getType() << endl;
		//cout << "++++++++++++++++++++++++++++++++++++" << endl;
		//cout << "currentNode: " << curPath << " --- type: " << curType << endl;
	}while(kFalse);
}

/********************************************************************************************************************
 *****Function: GetIssueParentSelected
 *****Creator:  Toan Nguyen
 *****IN: const PMString& path
 *****out: 
 *****Objective: 
 ********************************************************************************************************************/
string AMPIssuesDataModel::GetIssueParentSelected(const PMString& path) {
	do
	{
		AMPIssuesDataNode* parentNode = nil;
		std::map<PMString, AMPIssuesDataNode* >::const_iterator iterForParent = fPathNodeMap.find(path);
		if(iterForParent == fPathNodeMap.end()) {
			break;
		}
		parentNode = iterForParent->second;
		ASSERT(parentNode);
		
		//string curPath = parentNode->GetData().GrabCString();
		//typenode = parentNode->getNodeSelect();
		//cout << "++++++++++++++++++++++++++++++++++++" << endl;
		//cout << "parentPath3: " << parentNode->GetData().GrabCString() << endl;
		//cout << "parentName3: " << parentNode->GetNodeName().GrabCString() << endl;
		//cout << "parentImgPath3: " << parentNode->GetNodeID().GrabCString() << endl;
		//cout << "GetNodeImgPath3: " << parentNode->GetNodeImgPath().GrabCString() << endl;
		//cout << "parentDataType3: " << parentNode->getNodeSelect() << endl;
		//cout << "parentDataCheck3: " << parentNode->getType() << endl;
		//cout << "++++++++++++++++++++++++++++++++++++" << endl;
		
		string parentIssueSelect = parentNode->GetParent()->GetNodeName().GrabCString();
		//parentIssueSelect.erase(0,1);
		//parentIssueSelect.erase(parentIssueSelect.length()-1,parentIssueSelect.length());
		
		return parentIssueSelect;
		
	}while(kFalse);
	
	return "";
}

/********************************************************************************************************************
 *****Function: GetCurrentSelected
 *****Creator:  Toan Nguyen
 *****IN: const PMString& parentPath
 *****out: 
 *****Objective: 
 ********************************************************************************************************************/
int AMPIssuesDataModel::GetCurrentSelected(const PMString& parentPath)  {
	// We assume that the parent is cached, because we
	// found its kids
	do
	{
		int typenode = NODE_UNSELECTED;
		AMPIssuesDataNode* parentNode = nil;
		std::map<PMString, AMPIssuesDataNode* >::const_iterator iterForParent = fPathNodeMap.find(parentPath);
		if(iterForParent == fPathNodeMap.end()) {
			break;
		}
		parentNode = iterForParent->second;
		ASSERT(parentNode);
		
		int curType = parentNode->getType();
		string curPath = parentNode->GetData().GrabCString();
		typenode = parentNode->getNodeSelect();
		//cout << "++++++++++++++++++++++++++++++++++++" << endl;
		//cout << "parentPath3: " << parentNode->GetData().GrabCString() << endl;
		//cout << "parentName3: " << parentNode->GetNodeName().GrabCString() << endl;
		//cout << "parentImgPath3: " << parentNode->GetNodeID().GrabCString() << endl;
		//cout << "GetNodeImgPath3: " << parentNode->GetNodeImgPath().GrabCString() << endl;
		//cout << "parentDataType3: " << parentNode->getNodeSelect() << endl;
		//cout << "parentDataCheck3: " << parentNode->getType() << endl;
		//cout << "++++++++++++++++++++++++++++++++++++" << endl;
	
		return typenode;
		
	}while(kFalse);
	
	return NODE_UNSELECTED;
}

/********************************************************************************************************************
 *****Function: GetParamNodeSelected
 *****Creator:  Toan Nguyen
 *****IN: const PMString& parentPath, string *pageSelect, string *parentIssue
 *****out: 
 *****Objective: 
 ********************************************************************************************************************/
void AMPIssuesDataModel::GetParamNodeSelected(const PMString& parentPath, string *pageSelect, string *parentIssue)  {
	// We assume that the parent is cached, because we
	// found its kids
	do
	{
		int typenode = NODE_UNSELECTED;
		PMString tmpPath;
		AMPIssuesDataNode* parentNode = nil;
		
		std::map<PMString, AMPIssuesDataNode* >::const_iterator iterForParent = fPathNodeMap.find(parentPath);
		if(iterForParent == fPathNodeMap.end()) {
			break;
		}
		parentNode = iterForParent->second;
		ASSERT(parentNode);
		
		//int curType = parentNode->getType();
		//string curPath = parentNode->GetData().GrabCString();
		//cout << "++++++++++++++++++++++++++++++++++++" << endl;
		//cout << "parentPath3: " << parentNode->GetData().GrabCString() << endl;
		//cout << "parentName3: " << parentNode->GetNodeName().GrabCString() << endl;
		//cout << "parentImgPath3: " << parentNode->GetNodeID().GrabCString() << endl;
		//cout << "GetNodeImgPath3: " << parentNode->GetNodeImgPath().GrabCString() << endl;
		//cout << "parentDataType3: " << parentNode->getNodeSelect() << endl;
		//cout << "parentDataCheck3: " << parentNode->getType() << endl;
		//cout << "++++++++++++++++++++++++++++++++++++" << endl;
		//cout << "page number: " << parentNode->GetNodeNumber() << endl;
		stringstream ss; 
		ss << parentNode->GetNodeNumber();
		*pageSelect = ss.str();
		//*pageSelect = parentNode->GetNodeName().GrabCString();
		*parentIssue = parentNode->GetParent()->GetNodeName().GrabCString();
		
	}while(kFalse);
}

/********************************************************************************************************************
 *****Function: GetNthChildType
 *****Creator:  Toan Nguyen
 *****IN: const PMString& path, int32 nth
 *****out: 
 *****Objective: 
 ********************************************************************************************************************/
int AMPIssuesDataModel::GetNthChildType(const PMString& path, int32 nth) {
	std::map<PMString, AMPIssuesDataNode* >::const_iterator result = fPathNodeMap.find(path);
	if(result != fPathNodeMap.end()) {
		int32 possChildCount = result->second->ChildCount();
		if(possChildCount > 0) {
			// Again, distrust a node with zero child count, may be kids not yet cached 
			return result->second->GetNthChild(nth).getType();
		}
	}
	// Again, we may not have cached the kids.
	this->cacheChildren(path);
	// Don't recurse, as we may have no kids and we only want one try
	std::map<PMString, AMPIssuesDataNode* >::const_iterator postCacheResult = fPathNodeMap.find(path);
	if(postCacheResult != fPathNodeMap.end()) {
		return postCacheResult->second->GetNthChild(nth).getType();
	}
	
	return -1;
	
}

/********************************************************************************************************************
 *****Function: GetNthChildDataChecked
 *****Creator:  Toan Nguyen
 *****IN: const PMString& path, int32 nth
 *****out: 
 *****Objective: 
 ********************************************************************************************************************/
int AMPIssuesDataModel::GetNthChildDataChecked(const PMString& path, int32 nth) {
	std::map<PMString, AMPIssuesDataNode* >::const_iterator result = fPathNodeMap.find(path);
	if(result != fPathNodeMap.end()) {
		int32 possChildCount = result->second->ChildCount();
		if(possChildCount > 0) {
			// Again, distrust a node with zero child count, may be kids not yet cached 
			return result->second->GetNthChild(nth).getNodeSelect();
		}
	}
	// Again, we may not have cached the kids.
	this->cacheChildren(path);
	// Don't recurse, as we may have no kids and we only want one try
	std::map<PMString, AMPIssuesDataNode* >::const_iterator postCacheResult = fPathNodeMap.find(path);
	if(postCacheResult != fPathNodeMap.end()) {
		return postCacheResult->second->GetNthChild(nth).getNodeSelect();
	}
	
	return -1;
}

/********************************************************************************************************************
 *****Function: RereshData
 *****Creator:  Toan Nguyen
 *****IN: 
 *****out: 
 *****Objective: refresh database
 ********************************************************************************************************************/
void AMPIssuesDataModel::RereshData(const PMString& path)
{
	//cout << "refresh data model" << endl;
	if(path.empty() == kFalse) {
		cout << "refresh data model" << endl;
		fRootNode =  new AMPIssuesDataNode();
		//cout << "fRootNode path " << path.GrabCString() << endl;
		fRootNode->SetData(path);
		fRootNode->SetNodeName(path);
		fRootNode->setType(ROOT_NODE);
		fRootNode->setNodeSelect(NODE_UNSELECTED);
		fPathNodeMap.insert( std::pair<PMString, AMPIssuesDataNode* >(path, fRootNode));
		this->cacheChildren(path);
		cout << "refresh data model OK" << endl;
	}
}

/********************************************************************************************************************
 *****Function: deleteData
 *****Creator:  Toan Nguyen
 *****IN: 
 *****out: 
 *****Objective: delete data base
 ********************************************************************************************************************/
void AMPIssuesDataModel::deleteData(const PMString& path)
{
	//cout << "refresh data model" << endl;
	if(fRootNode != nil) {
		deleteTree();
	}
}

/********************************************************************************************************************
 *****Function: GetWidgetOnPanel
 *****Creator:  Toan Nguyen
 *****IN: const WidgetID& panelWidgetID, const WidgetID& widgetID
 *****out: 
 *****Objective: 
 ********************************************************************************************************************/
IControlView* AMPIssuesDataModel::GetWidgetOnPanel(const WidgetID& panelWidgetID, const WidgetID& widgetID)
{
	IControlView * controlView = nil;
	do {
		if(Utils<IPalettePanelUtils>() == nil) {
			break;
		}
		InterfacePtr<IPanelControlData> panelData (Utils<IPalettePanelUtils>()->QueryPanelByWidgetID(panelWidgetID));
		// Don't assert, fail silently, the tree view panel may be closed.
		if(panelData == nil)
		{
			cout << "allocate nil" << endl;
			break;
		}
		
		controlView = panelData->FindWidget(widgetID);
		ASSERT(controlView);
		if(controlView == nil)
		{
			cout << "return nil" << endl;
			break;
		}
		
	}while (kFalse);
	
	return controlView;
}

/********************************************************************************************************************
 *****Function: GetRootNumber
 *****Creator:  Toan Nguyen
 *****IN: 
 *****out: 
 *****Objective: get root number
 ********************************************************************************************************************/
int AMPIssuesDataModel::GetRootNumber() const {
	if(fRootNode != nil)
	{
		return fRootNode->GetNodeNumber();
	}
	return -1;
}

/********************************************************************************************************************
 *****Function: GetParentNumber
 *****Creator:  Toan Nguyen
 *****IN: const PMString& path
 *****out: 
 *****Objective: get parent number
 ********************************************************************************************************************/
int AMPIssuesDataModel::GetParentNumber(const PMString& path) const {
	// We assume that the parent is cached, because we
	// found its kids
	
	//cout << "GetParentType Path= " << path.GrabCString() << endl;
	std::map<PMString, AMPIssuesDataNode* >::const_iterator result = fPathNodeMap.find(path);
	if(result != fPathNodeMap.end())
	{
		AMPIssuesDataNode* node = result->second;
		ASSERT(node);
		ASSERT(fRootNode);
		// Use the comparison we've defined on the node class
		if((*node) == (*fRootNode))
		{
			return -1;
		}
		return node->GetParent()->GetNodeNumber();
	}
	
	
	return -1;
	
}

/********************************************************************************************************************
 *****Function: GetNthChildNumber
 *****Creator:  Toan Nguyen
 *****IN: const PMString& path, int32 nth
 *****out: 
 *****Objective: get child number nth
 ********************************************************************************************************************/
int AMPIssuesDataModel::GetNthChildNumber(const PMString& path, int32 nth) {
	std::map<PMString, AMPIssuesDataNode* >::const_iterator result = fPathNodeMap.find(path);
	if(result != fPathNodeMap.end()) {
		int32 possChildCount = result->second->ChildCount();
		if(possChildCount > 0) {
			// Again, distrust a node with zero child count, may be kids not yet cached 
			return result->second->GetNthChild(nth).GetNodeNumber();
		}
	}
	// Again, we may not have cached the kids.
	this->cacheChildren(path);
	// Don't recurse, as we may have no kids and we only want one try
	std::map<PMString, AMPIssuesDataNode* >::const_iterator postCacheResult = fPathNodeMap.find(path);
	if(postCacheResult != fPathNodeMap.end()) {
		return postCacheResult->second->GetNthChild(nth).GetNodeNumber();
	}
	
	return -1;
	
}

/********************************************************************************************************************
 *****Function: GetNodeStatus
 *****Creator:  Toan Nguyen
 *****IN: const PMString& parentPath
 *****out: 
 *****Objective: get node status returned
 ********************************************************************************************************************/
int AMPIssuesDataModel::GetNodeStatus(const PMString& parentPath)  {
	// We assume that the parent is cached, because we
	// found its kids
	do
	{
		AMPIssuesDataNode* parentNode = nil;
		std::map<PMString, AMPIssuesDataNode* >::const_iterator iterForParent = fPathNodeMap.find(parentPath);
		if(iterForParent == fPathNodeMap.end()) {
			break;
		}
		parentNode = iterForParent->second;
		ASSERT(parentNode);
		
		int curStatus = parentNode->getNodeStatus();
		return curStatus;
		
	}while(kFalse);
	
	return FALSE;
}

/********************************************************************************************************************
 *****Function: GetNodeIsEditing
 *****Creator:  Toan Nguyen
 *****IN: const PMString& parentPath
 *****out: 
 *****Objective: get node name is editing or not
 ********************************************************************************************************************/
int AMPIssuesDataModel::GetNodeIsEditing(const PMString& parentPath)  {
	// We assume that the parent is cached, because we
	// found its kids
	do
	{
		AMPIssuesDataNode* parentNode = nil;
		std::map<PMString, AMPIssuesDataNode* >::const_iterator iterForParent = fPathNodeMap.find(parentPath);
		if(iterForParent == fPathNodeMap.end()) {
			break;
		}
		parentNode = iterForParent->second;
		ASSERT(parentNode);
		
		int curStatus = parentNode->getNodeEditing();
		return curStatus;
		
	}while(kFalse);
	
	return FALSE;
}
//	end, File: AMPIssuesDataModel.cpp
